package com.cn.ant.modules.pay.cmbc.utils;

import cfca.sm2.signature.SM2PrivateKey;
import cfca.sm2rsa.common.Mechanism;
import cfca.sm2rsa.common.PKIException;
import cfca.util.CertUtil;
import cfca.util.EnvelopeUtil;
import cfca.util.KeyUtil;
import cfca.util.SignatureUtil2;
import cfca.util.cipher.lib.JCrypto;
import cfca.util.cipher.lib.Session;
import cfca.x509.certificate.X509Cert;
import cfca.x509.certificate.X509CertHelper;
import com.cn.ant.common.config.Global;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;

/**
 * 项目名称：linghang
 * 类名称：民生银行支付工具类
 * 类描述：民生银行支付工具类
 *
 * @version 1.0
 * @author：huanggenhua
 * @date：2017/6/15 7:44
 */
public class CMBCUtils {
    private static Session session;
    private static Logger logger = LoggerFactory.getLogger(CMBCUtils.class);

    /**
     * 初始化
     */
    private static void init(){
        try {
            if (session == null) {
                JCrypto.getInstance().initialize(JCrypto.JSOFT_LIB, null);
                session = JCrypto.getInstance().openSession(JCrypto.JSOFT_LIB);
            }
        } catch (PKIException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取签名
     * @param context
     * @return
     */
    public static String getSign(String context) {
        init();
        String priKeyAbsFile = Global.getConfig("merchantPrivateKey");
        String priKeyAbsPath = CMBCUtils.class.getClassLoader().getResource(priKeyAbsFile).getPath();
        String priKeyPWD = Global.getConfig("merchantPwd");
        String sign = "";
        try {
            //根据私钥和密码获取私密
            SM2PrivateKey priKey = KeyUtil.getPrivateKeyFromSM2(priKeyAbsPath, priKeyPWD);
            //签名
            sign = new String(
                    new SignatureUtil2().p1SignMessage(Mechanism.SM3_SM2, context.getBytes("UTF8"), priKey, session));
        } catch (PKIException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return sign;
    }

    /**
     * 组装需要加密的json串
     * @param sign
     * @param context
     * @return
     */
    public static String sign(String sign, String context) {
        GsonBuilder builder = new GsonBuilder();
        builder.disableHtmlEscaping();
        Gson gson = builder.create();
        Map<String, String> paramMap = new HashMap<String, String>();
        paramMap.put("sign", sign);
        paramMap.put("body", context);
        String signInfo = gson.toJson(paramMap); // 待加密字符串
        return signInfo;
    }

    /**
     * 加密报文
     * @param signContext
     * @return
     */
    public static String encrypt(String signContext) {
        init();
        String certAbsFile = Global.getConfig("bankPublicKey");
        String certAbsPath = CMBCUtils.class.getClassLoader().getResource(certAbsFile).getPath();
        X509Cert cert = null;
        try {
            cert = X509CertHelper.parse(certAbsPath);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (PKIException e) {
            e.printStackTrace();
        }
        X509Cert[] certs = { cert };
        byte[] encryptedData = null;
        try {
            encryptedData = EnvelopeUtil.envelopeMessage(signContext.getBytes("UTF8"), Mechanism.SM4_CBC, certs, session);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (PKIException e) {
            e.printStackTrace();
        }
        String encodeText = null;
        try {
            encodeText = new String(encryptedData, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return encodeText;
    }

    /**
     * 解密
     *
     * @param encryptContext
     *            需要解密的报文
     * @return
     */
    public static String dncrypt(String encryptContext) {
        logger.info("开始解密");
        init();
        String priKeyAbsFile = Global.getConfig("merchantPrivateKey");
        String priKeyAbsPath = CMBCUtils.class.getClassLoader().getResource(priKeyAbsFile).getPath();
        String priKeyPWD = Global.getConfig("merchantPwd");
        String decodeText = null;
        try {
            PrivateKey priKey = KeyUtil.getPrivateKeyFromSM2(priKeyAbsPath, priKeyPWD);
            X509Cert cert = CertUtil.getCertFromSM2(priKeyAbsPath);
            byte[] sourceData = EnvelopeUtil.openEvelopedMessage(encryptContext.getBytes("UTF8"), priKey, cert, session);
            decodeText = new String(sourceData, "UTF8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return decodeText;
    }

    /**
     * 验证签名
     *
     * @param dncryptContext
     *            需要验证签名的明文
     * @return
     */
    public static boolean signCheck(String dncryptContext) {
        logger.info("验证签名开始，报文为：" + dncryptContext);
        String certAbsFile = Global.getConfig("bankPublicKey");
        String certAbsPath = CMBCUtils.class.getClassLoader().getResource(certAbsFile).getPath();
        Gson gson = new Gson();
        @SuppressWarnings("unchecked")
        Map<String, Object> paraMap = gson.fromJson(dncryptContext, Map.class);
        //获取签名
        String sign = paraMap.get("sign").toString();
        //获取报文
        String body = paraMap.get("body").toString();
        boolean isSignOK = false;
        try {
            X509Cert cert = X509CertHelper.parse(certAbsPath);
            PublicKey pubKey = cert.getPublicKey();
            //签名验证
            isSignOK = new SignatureUtil2().p1VerifyMessage(Mechanism.SM3_SM2, body.getBytes("UTF8"),
                    sign.getBytes(), pubKey, session);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (isSignOK) {
            logger.info("验签通过");
        } else {
            logger.info("验签不通过");
        }
        return isSignOK;
    }
}
